﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область СлужебныйПрограммныйИнтерфейс

// Возвращает признак ошибки при запуске:
// 1) Ошибка загрузки сообщения обмена:
//    - ошибка загрузки идентификаторов объектов метаданных при загрузке сообщения обмена,
//    - ошибка проверки идентификаторов объектов метаданных,
//    - ошибка загрузки сообщения обмена перед обновлением ИБ,
//    - ошибка загрузки сообщения обмена перед обновлением ИБ в режиме когда версия не изменилась;
// 2) Ошибка обновления ИБ после успешной загрузки сообщения обмена.
//
Функция ПовторитьЗагрузкуСообщенияОбменаДаннымиПередЗапуском() Экспорт

	УстановитьПривилегированныйРежим(Истина);

	Возврат Константы.ПовторитьЗагрузкуСообщенияОбменаДаннымиПередЗапуском.Получить();

КонецФункции

// Параметры:
//  ИмяПараметра - Строка
//  УстановленныеПараметры - Массив из Строка
//
Процедура УстановкаПараметровСеанса(ИмяПараметра, УстановленныеПараметры) Экспорт
	
	// Инициализация параметров сеанса должна выполняться без обращения к параметрам работы программы.

	Если ИмяПараметра = "РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском" Тогда
		ПараметрыСеанса.РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском = Новый ФиксированнаяСтруктура(Новый Структура);
		УстановленныеПараметры.Добавить("РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском");
		Возврат;
	КонецЕсли;

	Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		
		// Процедура обновления повторно-используемых значений и параметров сеанса.
		ОбновитьКэшМеханизмаРегистрацииОбъектов();
		
		// Зарегистрируем имена параметров, которые установлены при.
		// Выполнении ОбменДаннымиВызовСервера.ОбновитьКэшМеханизмаРегистрацииОбъектов.
		УстановленныеПараметры.Добавить("ПравилаРегистрацииОбъектов");
		УстановленныеПараметры.Добавить("ДатаОбновленияПовторноИспользуемыхЗначенийМРО");

		ПараметрыСеанса.ПаролиСинхронизацииДанных = Новый ФиксированноеСоответствие(Новый Соответствие);
		УстановленныеПараметры.Добавить("ПаролиСинхронизацииДанных");

		ПараметрыСеанса.ПриоритетныеДанныеОбмена = Новый ФиксированныйМассив(Новый Массив);
		УстановленныеПараметры.Добавить("ПриоритетныеДанныеОбмена");

		ПараметрыСеанса.ПараметрыСеансаСинхронизацииДанных = Новый ХранилищеЗначения(Новый Соответствие);
		УстановленныеПараметры.Добавить("ПараметрыСеансаСинхронизацииДанных");

		СтруктураПроверки =Новый Структура;
		СтруктураПроверки.Вставить("ПроверятьРасхождениеВерсий", Ложь);
		СтруктураПроверки.Вставить("ЕстьОшибка", Ложь);
		СтруктураПроверки.Вставить("ТекстОшибки", "");

		ПараметрыСеанса.ОшибкаРасхожденияВерсийПриПолученииДанных = Новый ФиксированнаяСтруктура(СтруктураПроверки);
		УстановленныеПараметры.Добавить("ОшибкаРасхожденияВерсийПриПолученииДанных");

	Иначе

		ПараметрыСеанса.ПаролиСинхронизацииДанных = Новый ФиксированноеСоответствие(Новый Соответствие);
		УстановленныеПараметры.Добавить("ПаролиСинхронизацииДанных");

		ПараметрыСеанса.ПараметрыСеансаСинхронизацииДанных = Новый ХранилищеЗначения(Новый Соответствие);
		УстановленныеПараметры.Добавить("ПараметрыСеансаСинхронизацииДанных");
	КонецЕсли;

КонецПроцедуры

// Выполняет проверку актуальности КЭШа механизма регистрации объектов.
// Если кэш неактуальный, то выполняется инициализация КЭШа актуальными значениями.
//
// Параметры:
//  Нет.
// 
Процедура ПроверитьКэшМеханизмаРегистрацииОбъектов() Экспорт

	УстановитьПривилегированныйРежим(Истина);

	Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда

		АктуальнаяДата = ПолучитьФункциональнуюОпцию("АктуальнаяДатаОбновленияПовторноИспользуемыхЗначенийМРО");

		Если ПараметрыСеанса.ДатаОбновленияПовторноИспользуемыхЗначенийМРО <> АктуальнаяДата Тогда

			ОбновитьКэшМеханизмаРегистрацииОбъектов();

		КонецЕсли;

	КонецЕсли;

КонецПроцедуры

// Обновляет/устанавливает повторно-используемые значения и параметры сеанса для подсистемы обмена данными.
//
// Устанавливаемые параметры сеанса:
//   ПравилаРегистрацииОбъектов - ХранилищеЗначения - в бинарном виде содержит таблицу значений с правилами регистрации
//                                                    объектов.
//   ДатаОбновленияПовторноИспользуемыхЗначенийМРО - Дата (Дата и время) - содержит дату последнего актуального
//                                                                         кэша для подсистемы обмена данными.
//
Процедура ОбновитьКэшМеханизмаРегистрацииОбъектов() Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	ОбновитьПовторноИспользуемыеЗначения();
	Если ОбменДаннымиПовтИсп.ИспользуемыеПланыОбмена().Количество() > 0 Тогда
		
		ПараметрыСеанса.ПравилаРегистрацииОбъектов = Новый ХранилищеЗначения(ОбменДаннымиСервер.ПолучитьПравилаРегистрацииОбъектов());
		
	Иначе
		
		ПараметрыСеанса.ПравилаРегистрацииОбъектов = Новый ХранилищеЗначения(ОбменДаннымиСервер.ИнициализацияТаблицыПравилРегистрацииОбъектов());
		
	КонецЕсли;
	
	// Ключ для проверки актуальности кэша.
	ПараметрыСеанса.ДатаОбновленияПовторноИспользуемыхЗначенийМРО = 
		ПолучитьФункциональнуюОпцию("АктуальнаяДатаОбновленияПовторноИспользуемыхЗначенийМРО");

КонецПроцедуры

// Метод актуализирует значение константы ДатаОбновленияПовторноИспользуемыхЗначенийМРО.
// 
// Подробнее см. процедуру ОбменДаннымиВызовСервера.СброситьКэшМеханизмаРегистрацииОбъектов.
//
Процедура СброситьКэшМеханизмаРегистрацииОбъектов() Экспорт

	Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда

		УстановитьПривилегированныйРежим(Истина);
		// Записываем универсальную дату и время компьютера сервера - ТекущаяУниверсальнаяДата(),
		// метод ТекущаяДатаСеанса() использовать нельзя.
		// Текущая универсальная дата сервера в данном случае используется в качестве
		// ключа уникальности кэша механизма регистрации объектов.
		Константы.ДатаОбновленияПовторноИспользуемыхЗначенийМРО.Установить(ТекущаяУниверсальнаяДата());

	КонецЕсли;

КонецПроцедуры

// Возвращает список приоритетных данных обмена.
//
// Возвращаемое значение:
//  Массив - коллекция ссылок на выгруженные приоритетные данные обмена.
//
Функция ПриоритетныеДанныеОбмена() Экспорт

	УстановитьПривилегированныйРежим(Истина);

	Результат = Новый Массив;

	Для Каждого Элемент Из ПараметрыСеанса.ПриоритетныеДанныеОбмена Цикл

		Результат.Добавить(Элемент);

	КонецЦикла;

	Возврат Результат;
КонецФункции

// Очищает список приоритетных данных обмена.
//
Процедура ОчиститьПриоритетныеДанныеОбмена() Экспорт

	УстановитьПривилегированныйРежим(Истина);

	ПараметрыСеанса.ПриоритетныеДанныеОбмена = Новый ФиксированныйМассив(Новый Массив);

КонецПроцедуры

// Дополняет список приоритетных данных обмена переданным значением.
//
Процедура ДополнитьПриоритетныеДанныеОбмена(Знач Данные) Экспорт

	Результат = ПриоритетныеДанныеОбмена();

	Результат.Добавить(Данные);

	УстановитьПривилегированныйРежим(Истина);

	ПараметрыСеанса.ПриоритетныеДанныеОбмена = Новый ФиксированныйМассив(Результат);

КонецПроцедуры

// Возвращает признак режима загрузки параметров работы программы из сообщения обмена в информационную базу.
// Актуально для обмена в РИБ при загрузке данных в подчиненном узле РИБ.
//
Функция РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском(Свойство) Экспорт

	УстановитьПривилегированныйРежим(Истина);

	Возврат ПараметрыСеанса.РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском.Свойство(Свойство);

КонецФункции

// Возвращает признак использования плана обмена в обмене данными.
// Если план обмена содержит хотя бы один узел кроме предопределенного,
// то считается, что он используется.
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя плана обмена, как оно задано в конфигураторе.
//
// Возвращаемое значение:
//  Булево - Истина, если план обмена используется, Ложь - нет.
//
Функция ОбменДаннымиВключен(Знач ИмяПланаОбмена, Знач Отправитель) Экспорт

	УстановитьПривилегированныйРежим(Истина);

	Возврат ОбменДаннымиПовтИсп.ОбменДаннымиВключен(ИмяПланаОбмена, Отправитель);
КонецФункции

// Возвращает значение параметра сеанса ПравилаРегистрацииОбъектов, полученное в привилегированном режиме.
//
// Возвращаемое значение:
//  ХранилищеЗначения - значение параметра сеанса ПравилаРегистрацииОбъектов.
//
Функция ПараметрыСеансаПравилаРегистрацииОбъектов() Экспорт

	УстановитьПривилегированныйРежим(Истина);

	Возврат ПараметрыСеанса.ПравилаРегистрацииОбъектов;

КонецФункции

// Возвращает признак того, что для получателя зарегистрированы изменения данных.
//
// Возвращаемое значение:
//  Булево - Истина, если есть зарегистрированные данные, Ложь - нет.
//
Функция ИзмененияЗарегистрированы(Знач Получатель) Экспорт

	ТекстЗапроса =
	"ВЫБРАТЬ ПЕРВЫЕ 1 1
	|ИЗ
	|	&ИмяТаблицыИзменения КАК ТаблицаИзменений
	|ГДЕ
	|	ТаблицаИзменений.Узел = &Узел";

	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Узел", Получатель);

	УстановитьПривилегированныйРежим(Истина);

	СтрокаШаблона = "%1.Изменения";

	СоставПланаОбмена = Метаданные.ПланыОбмена[ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(Получатель)].Состав;
	Для Каждого ЭлементСостава Из СоставПланаОбмена Цикл

		ИмяТаблицыИзменения = СтрШаблон(СтрокаШаблона, ЭлементСостава.Метаданные.ПолноеИмя());

		Запрос.Текст = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицыИзменения", ИмяТаблицыИзменения);
		РезультатЗапроса = Запрос.Выполнить();

		Если Не РезультатЗапроса.Пустой() Тогда
			Возврат Истина;
		КонецЕсли;

	КонецЦикла;

	Возврат Ложь;
КонецФункции

// Только для внутреннего использования.
//
// Параметры:
//   ИдентификаторФайла - УникальныйИдентификатор - уникальный идентификатор сессии передачи данных.
//   НомерЗагружаемойЧастиФайла - Число - номер части файла.
//   ЗагружаемаяЧастьФайла - ДвоичныеДанные - данные части файла.
//   СообщениеОбОшибке - Строка - описание ошибки при выполнении операции.
//
Функция ЗагрузитьЧастьФайла(ИдентификаторФайла, НомерЗагружаемойЧастиФайла, ЗагружаемаяЧастьФайла, СообщениеОбОшибке) Экспорт

	СообщениеОбОшибке = "";

	Если Не ЗначениеЗаполнено(ИдентификаторФайла) Тогда
		СообщениеОбОшибке = НСтр("ru = 'Не указан идентификатор загружаемого файла. Дальнейшее выполнение метода невозможно.
								|Назначьте уникальный идентификатор для загружаемого файла.'");
		ВызватьИсключение (СообщениеОбОшибке);
	КонецЕсли;

	Если Не ЗначениеЗаполнено(ЗагружаемаяЧастьФайла) И ТипЗнч(ЗагружаемаяЧастьФайла) <> Тип("ДвоичныеДанные") Тогда
		СообщениеОбОшибке = НСтр(
			"ru = 'Метод не может быть выполнен, т.к. переданные данные не соответствуют типу для получения данных.'");
		ВызватьИсключение (СообщениеОбОшибке);
	КонецЕсли;

	Если Не ЗначениеЗаполнено(НомерЗагружаемойЧастиФайла) Или НомерЗагружаемойЧастиФайла = 0 Тогда
		НомерЗагружаемойЧастиФайла = 1;
	КонецЕсли;

	КаталогВременныхФайлов = ВременныйКаталогВыгрузки(ИдентификаторФайла);

	Каталог = Новый Файл(КаталогВременныхФайлов);
	Если Не Каталог.Существует() Тогда
		СоздатьКаталог(КаталогВременныхФайлов);
	КонецЕсли;

	ИмяФайла = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(КаталогВременныхФайлов, ПолучитьИмяЧастиФайла(
		НомерЗагружаемойЧастиФайла));
	ЗагружаемаяЧастьФайла.Записать(ИмяФайла);

	Возврат "";

КонецФункции

Функция ВыгрузитьЧастьФайла(ИдентификаторФайла, НомерВыгружаемойЧастиФайла, СообщениеОбОшибке) Экспорт

	СообщениеОбОшибке      = "";
	ИмяЧастиФайла          = "";
	КаталогВременныхФайлов = ВременныйКаталогВыгрузки(ИдентификаторФайла);

	Для КоличествоРазрядов = СтрДлина(Формат(НомерВыгружаемойЧастиФайла, "ЧДЦ=0; ЧГ=0")) По 5 Цикл

		ФорматнаяСтрока = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("ЧЦ=%1; ЧВН=; ЧГ=0", Строка(
			КоличествоРазрядов));

		ИмяФайла = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("%1.zip.%2", ИдентификаторФайла, Формат(
			НомерВыгружаемойЧастиФайла, ФорматнаяСтрока));

		ИменаФайлов = НайтиФайлы(КаталогВременныхФайлов, ИмяФайла);

		Если ИменаФайлов.Количество() > 0 Тогда

			ИмяЧастиФайла = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(КаталогВременныхФайлов, ИмяФайла);
			Прервать;

		КонецЕсли;

	КонецЦикла;

	ЧастьФайла = Новый Файл(ИмяЧастиФайла);

	Если ЧастьФайла.Существует() Тогда
		Возврат Новый ДвоичныеДанные(ИмяЧастиФайла);
	Иначе
		СообщениеОбОшибке = НСтр("ru = 'Часть файла с указанным номером не найдена.'");
	КонецЕсли;

КонецФункции

Функция ПодготовитьФайлДляЗагрузки(ИдентификаторФайла, СообщениеОбОшибке) Экспорт

	УстановитьПривилегированныйРежим(Истина);

	ИдентификаторФайлаВоВременномХранилище = "";

	КаталогВременныхФайлов = ВременныйКаталогВыгрузки(ИдентификаторФайла);
	ИмяАрхива              = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(КаталогВременныхФайлов, "datafile.zip");

	МассивПолученныхФайлов = НайтиФайлы(КаталогВременныхФайлов, "data.zip.*");

	Если МассивПолученныхФайлов.Количество() > 0 Тогда

		ФайлыДляОбъединения = Новый Массив;
		ИмяЧастиФайла = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(КаталогВременныхФайлов, "data.zip.%1");

		Для НомерЧасти = 1 По МассивПолученныхФайлов.Количество() Цикл
			ФайлыДляОбъединения.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ИмяЧастиФайла,
				НомерЧасти));
		КонецЦикла;

	Иначе
		ШаблонСообщения = НСтр("ru = 'Не найден ни один фрагмент сессии передачи с идентификатором %1.
							|Убедитесь, что в настройках программы заданы параметры
							|""Каталог временных файлов для Linux"" и ""Каталог временных файлов для Windows"".'");
		СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, Строка(
			ИдентификаторФайла));
		ВызватьИсключение (СообщениеОбОшибке);
	КонецЕсли;

	Попытка
		ОбъединитьФайлы(ФайлыДляОбъединения, ИмяАрхива);
	Исключение
		СообщениеОбОшибке = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		ВызватьИсключение (СообщениеОбОшибке);
	КонецПопытки;
	
	// Распаковать.
	Разархиватор = Новый ЧтениеZipФайла(ИмяАрхива);

	Если Разархиватор.Элементы.Количество() = 0 Тогда

		Попытка
			УдалитьФайлы(КаталогВременныхФайлов);
		Исключение
			СообщениеОбОшибке = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
			ЗаписьЖурналаРегистрации(ОбменДаннымиСервер.СобытиеЖурналаРегистрацииУдалениеВременногоФайла(),
				УровеньЖурналаРегистрации.Ошибка, , , СообщениеОбОшибке);
			ВызватьИсключение (СообщениеОбОшибке);
		КонецПопытки;

		СообщениеОбОшибке = НСтр("ru = 'Файл архива не содержит данных.'");
		ВызватьИсключение (СообщениеОбОшибке);

	КонецЕсли;

	ЭлементАрхива = Разархиватор.Элементы.Получить(0);
	ИмяФайла = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(КаталогВременныхФайлов, ЭлементАрхива.Имя);

	Разархиватор.Извлечь(ЭлементАрхива, КаталогВременныхФайлов);
	Разархиватор.Закрыть();
	
	// Помещаем файл в каталог временного хранилища файлов.
	КаталогЗагрузки          = ОбменДаннымиСервер.КаталогВременногоХранилищаФайлов();
	ИмяФайлаСДанными         = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(ИдентификаторФайла,
		ОбщегоНазначенияКлиентСервер.ПолучитьРасширениеИмениФайла(ИмяФайла));
	ИмяФайлаВКаталогеЗагрузки = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(КаталогЗагрузки, ИмяФайлаСДанными);

	Попытка
		ПереместитьФайл(ИмяФайла, ИмяФайлаВКаталогеЗагрузки);
	Исключение
		СообщениеОбОшибке = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ЗаписьЖурналаРегистрации(ОбменДаннымиСервер.СобытиеЖурналаРегистрацииУдалениеВременногоФайла(),
			УровеньЖурналаРегистрации.Ошибка, , , СообщениеОбОшибке);
		ВызватьИсключение (СообщениеОбОшибке);
	КонецПопытки;

	ИдентификаторФайлаВоВременномХранилище = ОбменДаннымиСервер.ПоместитьФайлВХранилище(ИмяФайлаВКаталогеЗагрузки);
	
	// Удаляем временные файлы.
	Попытка
		УдалитьФайлы(КаталогВременныхФайлов);
	Исключение
		СообщениеОбОшибке = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ЗаписьЖурналаРегистрации(ОбменДаннымиСервер.СобытиеЖурналаРегистрацииУдалениеВременногоФайла(),
			УровеньЖурналаРегистрации.Ошибка, , , СообщениеОбОшибке);
		ВызватьИсключение (СообщениеОбОшибке);
	КонецПопытки;

	Возврат ИдентификаторФайлаВоВременномХранилище;

КонецФункции

Процедура ПодготовитьДанныеДляВыгрузкиИзИнформационнойБазы(ПараметрыПроцедуры, АдресХранилища) Экспорт

	ПараметрыWEBСервиса = ПараметрыПроцедуры["ПараметрыWEBСервиса"];
	СообщениеОбОшибке   = ПараметрыПроцедуры["СообщениеОбОшибке"];

	УстановитьПривилегированныйРежим(Истина);

	КомпонентыОбмена = КомпонентыОбмена("Отправка", ПараметрыWEBСервиса);
	ИмяФайла         = Строка(Новый УникальныйИдентификатор) + ".xml";

	КаталогВременныхФайлов = ОбменДаннымиСервер.КаталогВременногоХранилищаФайлов();
	ПолноеИмяФайла         = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(
		КаталогВременныхФайлов, ИмяФайла);
		
	// Открываем файл обмена.
	ОбменДаннымиXDTOСервер.ОткрытьФайлВыгрузки(КомпонентыОбмена, ПолноеИмяФайла);

	Если КомпонентыОбмена.ФлагОшибки Тогда
		КомпонентыОбмена.ФайлОбмена = Неопределено;

		ОбменДаннымиXDTOСервер.ЗавершитьВедениеПротоколаОбмена(КомпонентыОбмена);

		ВызватьИсключение КомпонентыОбмена.СтрокаСообщенияОбОшибке;
	КонецЕсли;

	СтруктураНастроекОбмена = СтруктураНастроекОбмена(КомпонентыОбмена, Перечисления.ДействияПриОбмене.ВыгрузкаДанных);
	
	// Выгрузка данных.
	Попытка
		ОбменДаннымиXDTOСервер.ПроизвестиВыгрузкуДанных(КомпонентыОбмена);
	Исключение

		Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена Тогда
			РазблокироватьДанныеДляРедактирования(КомпонентыОбмена.УзелКорреспондента);
		КонецЕсли;

		Инфо = ИнформацияОбОшибке();
		КодОшибки = Новый Структура("КраткоеПредставлениеОшибки, ПодробноеПредставлениеОшибки",
			ОбработкаОшибок.КраткоеПредставлениеОшибки(Инфо), ОбработкаОшибок.ПодробноеПредставлениеОшибки(Инфо));

		ОбменДаннымиXDTOСервер.ЗаписатьВПротоколВыполнения(КомпонентыОбмена, КодОшибки);
		ОбменДаннымиXDTOСервер.ЗавершитьВедениеПротоколаОбмена(КомпонентыОбмена);

		КомпонентыОбмена.ФайлОбмена = Неопределено;

		ВызватьИсключение КодОшибки.КраткоеПредставлениеОшибки;
	КонецПопытки;

	КомпонентыОбмена.ФайлОбмена.Закрыть();

	ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена, КомпонентыОбмена);

	Если КомпонентыОбмена.ФлагОшибки Тогда

		СообщениеОбОшибке = КомпонентыОбмена.СтрокаСообщенияОбОшибке;
		ВызватьИсключение СообщениеОбОшибке;

	Иначе
		
		// Поместить файл во временное хранилище.
		ИдентификаторФайлаВоВременномХранилище = Строка(ОбменДаннымиСервер.ПоместитьФайлВХранилище(ПолноеИмяФайла));
		
		// Создаем временный каталог для хранения частей файла данных.
		ВременныйКаталог                     = ВременныйКаталогВыгрузки(
			ИдентификаторФайлаВоВременномХранилище);
		ИмяНеразделенногоФайла               = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(
			ВременныйКаталог, ИдентификаторФайлаВоВременномХранилище + ?(ПараметрыWEBСервиса.РазмерЧастиФайла > 0,
			".zip", ".zip.1"));
		ИмяИсходногоФайлаВоВременномКаталоге = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(
			ВременныйКаталог, "data.xml");

		СоздатьКаталог(ВременныйКаталог);
		КопироватьФайл(ПолноеИмяФайла, ИмяИсходногоФайлаВоВременномКаталоге);
		
		// Архивируем файл.
		Архиватор = Новый ЗаписьZipФайла(ИмяНеразделенногоФайла);
		Архиватор.Добавить(ИмяИсходногоФайлаВоВременномКаталоге);
		Архиватор.Записать();

		Если ПараметрыWEBСервиса.РазмерЧастиФайла > 0 Тогда
			// Разделение файла на части.
			ИменаФайлов = РазделитьФайл(ИмяНеразделенногоФайла, ПараметрыWEBСервиса.РазмерЧастиФайла * 1024);
		Иначе
			ИменаФайлов = Новый Массив;
			ИменаФайлов.Добавить(ИмяНеразделенногоФайла);
		КонецЕсли;

		ВозвращаемоеЗначение = "{WEBService}$%1$%2";
		ВозвращаемоеЗначение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ВозвращаемоеЗначение,
			ИменаФайлов.Количество(), ИдентификаторФайлаВоВременномХранилище);

		Сообщение = Новый СообщениеПользователю;
		Сообщение.Текст = ВозвращаемоеЗначение;
		Сообщение.Сообщить();

	КонецЕсли;

КонецПроцедуры

Процедура ЗагрузитьДанныеXDTOВИнформационнуюБазу(ПараметрыПроцедуры, АдресХранилища) Экспорт

	ПараметрыWEBСервиса = ПараметрыПроцедуры["ПараметрыWEBСервиса"];
	СообщениеОбОшибке   = ПараметрыПроцедуры["СообщениеОбОшибке"];

	УстановитьПривилегированныйРежим(Истина);

	Отказ = Ложь;
	КомпонентыОбмена = КомпонентыОбмена("Получение", ПараметрыWEBСервиса, Отказ);

	Если КомпонентыОбмена.ФлагОшибки Тогда
		СообщениеОбОшибке = КомпонентыОбмена.СтрокаСообщенияОбОшибке;
		ВызватьИсключение СообщениеОбОшибке;
	КонецЕсли;

	СтруктураНастроекОбмена = СтруктураНастроекОбмена(КомпонентыОбмена, Перечисления.ДействияПриОбмене.ЗагрузкаДанных);

	Если Не Отказ Тогда
		ОтключитьОбновлениеКлючейДоступа(Истина);
		Попытка
			ОбменДаннымиXDTOСервер.ПроизвестиЧтениеДанных(КомпонентыОбмена);
			ОтключитьОбновлениеКлючейДоступа(Ложь);
		Исключение
			ОтключитьОбновлениеКлючейДоступа(Ложь);
			Информация = ИнформацияОбОшибке();
			СообщениеОбОшибке = НСтр("ru = 'Ошибка при загрузке данных: %1'");
			СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				СообщениеОбОшибке, ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация));
			ОбменДаннымиXDTOСервер.ЗаписатьВПротоколВыполнения(КомпонентыОбмена, СообщениеОбОшибке, , , , , Истина);
			КомпонентыОбмена.ФлагОшибки = Истина;
		КонецПопытки;

		ОтключитьОбновлениеКлючейДоступа(Истина);
		Попытка
			ОбменДаннымиXDTOСервер.УдалитьВременныеОбъектыСозданныеПоСсылкам(КомпонентыОбмена);
			ОтключитьОбновлениеКлючейДоступа(Ложь);
		Исключение
			ОтключитьОбновлениеКлючейДоступа(Ложь);
			Информация = ИнформацияОбОшибке();
			СообщениеОбОшибке = НСтр("ru = 'Ошибка при удалении временных объектов, созданных по ссылкам: %1'");
			СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				СообщениеОбОшибке, ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация));
			ОбменДаннымиXDTOСервер.ЗаписатьВПротоколВыполнения(КомпонентыОбмена, СообщениеОбОшибке, , , , , Истина);
			КомпонентыОбмена.ФлагОшибки = Истина;
		КонецПопытки;

		КомпонентыОбмена.ФайлОбмена.Закрыть();
	Иначе
		КомпонентыОбмена.ФлагОшибки = Истина;
	КонецЕсли;

	ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена, КомпонентыОбмена);

	Если КомпонентыОбмена.ФлагОшибки Тогда
		ВызватьИсключение КомпонентыОбмена.СтрокаСообщенияОбОшибке;
	КонецЕсли;

	Если Не КомпонентыОбмена.ФлагОшибки И КомпонентыОбмена.ЭтоОбменЧерезПланОбмена
		И КомпонентыОбмена.ИспользоватьКвитирование Тогда
		
		// Запишем информацию о номере входящего сообщения.
		НачатьТранзакцию();
		Попытка
			Блокировка = Новый БлокировкаДанных;
			ЭлементБлокировки = Блокировка.Добавить(ОбщегоНазначения.ИмяТаблицыПоСсылке(
				КомпонентыОбмена.УзелКорреспондента));
			ЭлементБлокировки.УстановитьЗначение("Ссылка", КомпонентыОбмена.УзелКорреспондента);
			Блокировка.Заблокировать();

			ЗаблокироватьДанныеДляРедактирования(КомпонентыОбмена.УзелКорреспондента);
			ОбъектУзла = КомпонентыОбмена.УзелКорреспондента.ПолучитьОбъект();

			ОбъектУзла.НомерПринятого = КомпонентыОбмена.НомерВходящегоСообщения;
			ОбъектУзла.ДополнительныеСвойства.Вставить("ПолучениеСообщенияОбмена");

			ОбъектУзла.Записать();

			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			ВызватьИсключение;
		КонецПопытки;

	КонецЕсли;

КонецПроцедуры

Функция ВременныйКаталогВыгрузки(Знач ИдентификаторСессии) Экспорт

	УстановитьПривилегированныйРежим(Истина);

	ВременныйКаталог = "{ИдентификаторСессии}";
	ВременныйКаталог = СтрЗаменить(ВременныйКаталог, "ИдентификаторСессии", Строка(ИдентификаторСессии));

	Результат = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(
		ОбменДаннымиСервер.КаталогВременногоХранилищаФайлов(), ВременныйКаталог);

	Возврат Результат;

КонецФункции

Процедура ПроверитьБлокировкуИнформационнойБазыДляОбновления() Экспорт

	Если ЗначениеЗаполнено(ОбновлениеИнформационнойБазыСлужебный.ИнформационнаяБазаЗаблокированаДляОбновления()) Тогда

		ВызватьИсключение НСтр("ru = 'Синхронизация данных временно недоступна в связи с обновлением приложения.'");

	КонецЕсли;

КонецПроцедуры

Функция ПолучитьСтатусВыполненияПолученияДанных(ИдентификаторДлительнойОперации, СообщениеОбОшибке) Экспорт

	СообщениеОбОшибке = "";

	УстановитьПривилегированныйРежим(Истина);
	ФоновоеЗадание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(
		Новый УникальныйИдентификатор(ИдентификаторДлительнойОперации));

	СостоянияФоновогоЗадания = СостоянияФоновыхЗаданий();
	Если ФоновоеЗадание = Неопределено Тогда
		СостояниеТекущегоФоновогоЗадания = СостоянияФоновогоЗадания.Получить(СостояниеФоновогоЗадания.Отменено);
	Иначе

		Если ФоновоеЗадание.ИнформацияОбОшибке <> Неопределено Тогда
			СообщениеОбОшибке = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ФоновоеЗадание.ИнформацияОбОшибке);
		КонецЕсли;
		СостояниеТекущегоФоновогоЗадания = СостоянияФоновогоЗадания.Получить(ФоновоеЗадание.Состояние);

	КонецЕсли;

	Возврат СостояниеТекущегоФоновогоЗадания;

КонецФункции

Функция ПолучитьСтатусВыполненияПодготовкиДанныхКОтправке(ИдентификаторФоновогоЗадания, СообщениеОбОшибке) Экспорт

	СообщениеОбОшибке = "";

	УстановитьПривилегированныйРежим(Истина);

	ВозвращаемаяСтруктура = ФабрикаXDTO.Создать(
		ФабрикаXDTO.Тип("http://v8.1c.ru/SSL/Exchange/EnterpriseDataExchange", "PrepareDataOperationResult"));

	ФоновоеЗадание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(
		Новый УникальныйИдентификатор(ИдентификаторФоновогоЗадания));

	Если ФоновоеЗадание = Неопределено Тогда
		СостояниеТекущегоФоновогоЗадания = СостоянияФоновыхЗаданий().Получить(СостояниеФоновогоЗадания.Отменено);
	Иначе

		СообщениеОбОшибке        = "";
		КоличествоЧастейФайла    = 0;
		ИдентификаторФайла       = "";
		СостояниеТекущегоФоновогоЗадания = СостоянияФоновыхЗаданий().Получить(ФоновоеЗадание.Состояние);

		Если ФоновоеЗадание.ИнформацияОбОшибке <> Неопределено Тогда
			СообщениеОбОшибке = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ФоновоеЗадание.ИнформацияОбОшибке);
		Иначе
			Если ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Завершено Тогда
				МассивСообщений  = ДлительныеОперации.СообщенияПользователю(Истина, ФоновоеЗадание.УникальныйИдентификатор);
				Для Каждого СообщениеФоновогоЗадания Из МассивСообщений Цикл
					Если СтрНайти(СообщениеФоновогоЗадания.Текст, "{WEBService}") > 0 Тогда
						МассивРезультата = СтрРазделить(СообщениеФоновогоЗадания.Текст, "$", Истина);
						КоличествоЧастейФайла = МассивРезультата[1];
						ИдентификаторФайла    = МассивРезультата[2];
						Прервать;
					Иначе
						Продолжить;
					КонецЕсли;
				КонецЦикла;
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;

	ВозвращаемаяСтруктура.ErrorMessage = СообщениеОбОшибке;
	ВозвращаемаяСтруктура.FileID       = ИдентификаторФайла;
	ВозвращаемаяСтруктура.PartCount    = КоличествоЧастейФайла;
	ВозвращаемаяСтруктура.Status       = СостояниеТекущегоФоновогоЗадания;

	Возврат ВозвращаемаяСтруктура;

КонецФункции

Функция ИнициализироватьПараметрыWebСервиса() Экспорт

	СтруктураПараметров = Новый Структура;
	СтруктураПараметров.Вставить("ИмяПланаОбмена");
	СтруктураПараметров.Вставить("КодУзлаПланаОбмена");
	СтруктураПараметров.Вставить("ИдентификаторФайлаВоВременномХранилище");
	СтруктураПараметров.Вставить("РазмерЧастиФайла");
	СтруктураПараметров.Вставить("ИмяWEBСервиса");

	Возврат СтруктураПараметров;

КонецФункции

Процедура ОтключитьОбновлениеКлючейДоступа(Отключить, ПланироватьОбновление = Истина) Экспорт

	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда
		МодульУправлениеДоступом = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступом");
		МодульУправлениеДоступом.ОтключитьОбновлениеКлючейДоступа(Отключить, ПланироватьОбновление);
	КонецЕсли;

КонецПроцедуры

Процедура ПоместитьСообщениеДляСопоставленияДанных(УзелОбмена, ИдентификаторСообщения) Экспорт

	УстановитьПривилегированныйРежим(Истина);
	
	// Удаляется предыдущее сообщение для сопоставления данных.
	Отбор = Новый Структура("УзелИнформационнойБазы", УзелОбмена);
	ОбщиеНастройки = РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.Получить(Отбор);

	Если ЗначениеЗаполнено(ОбщиеНастройки.СообщениеДляСопоставленияДанных) Тогда
		ИмяВременногоФайла = "";
		Попытка
			ИмяВременногоФайла = ОбменДаннымиСервер.ПолучитьФайлИзХранилища(
				ОбщиеНастройки.СообщениеДляСопоставленияДанных);
		Исключение
			РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.ПоместитьСообщениеДляСопоставленияДанных(
				УзелОбмена, "");
		КонецПопытки;

		Если Не ПустаяСтрока(ИмяВременногоФайла) Тогда
			Файл = Новый Файл(ИмяВременногоФайла);
			Если Файл.Существует() И Файл.ЭтоФайл() Тогда
				Попытка
					УдалитьФайлы(ИмяВременногоФайла);
				Исключение
					// Возвращаем информацию о файле во временное хранилище,
					// для последующего удаления через регл. задание.
					ОбменДаннымиСервер.ПоместитьФайлВХранилище(ИмяВременногоФайла,
						ОбщиеНастройки.СообщениеДляСопоставленияДанных);
				КонецПопытки;
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;

	РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.ПоместитьСообщениеДляСопоставленияДанных(
		УзелОбмена, ИдентификаторСообщения);

КонецПроцедуры

// Получает состояние длительной операции (фонового задания), выполняемой в базе-корреспонденте для узла информационной
// базы.
//
Функция СостояниеДлительнойОперацииДляУзлаИнформационнойБазы(Знач ИдентификаторОперации, Знач УзелИнформационнойБазы,
	Знач ПараметрыАутентификации = Неопределено, СтрокаСообщенияОбОшибке = "") Экспорт

	УстановитьПривилегированныйРежим(Истина);

	ПараметрыПодключения = РегистрыСведений.НастройкиТранспортаОбменаДанными.НастройкиТранспортаWS(
		УзелИнформационнойБазы, ПараметрыАутентификации);

	ВерсииИнтерфейса = ОбменДаннымиПовтИсп.ВерсииКорреспондента(ПараметрыПодключения);

	СообщениеОбОшибке = "";
	ДополнительныеПараметры = Неопределено;
	Прокси = ОбменДаннымиВебСервис.WSПроксиДляУзлаИнформационнойБазы(УзелИнформационнойБазы, СообщениеОбОшибке, ДополнительныеПараметры);

	Если Прокси = Неопределено Тогда
		ВызватьИсключение СтрокаСообщенияОбОшибке;
	КонецЕсли;
	
	ПараметрыПрокси = Новый Структура("ТекущаяВерсия", ДополнительныеПараметры.ТекущаяВерсия);
	ПараметрыОбмена = Новый Структура("ИдентификаторОперации", ИдентификаторОперации);
	СтруктураНастроекОбмена = ОбменДаннымиСервер.НастройкиОбменаДляУзлаИнформационнойБазы(УзелИнформационнойБазы,
		"ПроверкаСостоянияДлительнойОперации", Перечисления.ВидыТранспортаСообщенийОбмена.WS, Ложь);
	
	Результат = ОбменДаннымиВебСервис.ПолучитьСтатусДлительнойОперации(Прокси, ПараметрыПрокси.ТекущаяВерсия, СтруктураНастроекОбмена, ПараметрыОбмена, СтрокаСообщенияОбОшибке);
	
	Если Результат = "Failed" Тогда
		СтрокаСообщения = НСтр("ru = 'Ошибка в базе-корреспонденте: %1'");
		СтрокаСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения,
			СтрокаСообщенияОбОшибке);
	КонецЕсли;

	Возврат Результат;

КонецФункции

// Устанавливает признак необходимости загрузки расширений
Процедура ВключитьЗагрузкуРасширенийИзменяющиеСтруктуруДанных() Экспорт

	УстановитьПривилегированныйРежим(Истина);

	Константы.ЗагрузитьРасширенияИзменяющиеСтруктуруДанных.Установить(Истина);

КонецПроцедуры

// Сбрасывает признак необходимости загрузки расширения
Процедура ОтключитьЗагрузкуРасширенийИзменяющихСтруктуруДанных() Экспорт

	УстановитьПривилегированныйРежим(Истина);

	Если Константы.ЗагрузитьРасширенияИзменяющиеСтруктуруДанных.Получить() Тогда
		Константы.ЗагрузитьРасширенияИзменяющиеСтруктуруДанных.Установить(Ложь);
	КонецЕсли;

КонецПроцедуры

// Возвращает признак необходимости загрузки расширений
Функция ЗагрузитьРасширенияИзменяющиеСтруктуруДанных() Экспорт

	УстановитьПривилегированныйРежим(Истина);

	Возврат Константы.ЗагрузитьРасширенияИзменяющиеСтруктуруДанных.Получить()

КонецФункции

#Область ВыполнениеОбменаМетодамиСериализации

// Возвращает таблицу предопределенных данных информационной базы.
//
// Возвращаемое значение:
//   ТаблицаЗначений - набор предопределенных элементов:
//     * ИмяТаблицы - Строка - имя таблицы ИБ.
//     * ИмяТипаXML - Строка - имя типа сериализованного объекта.
//     * Ссылка - ЛюбаяСсылка - ссылка на предопределенный элемент данных.
//     * ИмяПредопределенныхДанных - Строка - имя предопределенного элемента.
// 
Функция ТаблицаПредопределенныхДанных() Экспорт

	ТаблицаПредопределенных = Новый ТаблицаЗначений;
	ТаблицаПредопределенных.Колонки.Добавить("ИмяТаблицы");
	ТаблицаПредопределенных.Колонки.Добавить("ИмяТипаXML");
	ТаблицаПредопределенных.Колонки.Добавить("Ссылка");
	ТаблицаПредопределенных.Колонки.Добавить("ИмяПредопределенныхДанных");

	ВидыМетаданных = Новый Массив;
	ВидыМетаданных.Добавить(Метаданные.Справочники);
	ВидыМетаданных.Добавить(Метаданные.ПланыВидовРасчета);
	ВидыМетаданных.Добавить(Метаданные.ПланыВидовХарактеристик);
	ВидыМетаданных.Добавить(Метаданные.ПланыСчетов);

	ПакетЗапросов = Новый Массив; // Массив из Запрос
	СчетчикТаблиц = 0;
	ТекстЗапроса  = "";

	Для Каждого ВидМетаданных Из ВидыМетаданных Цикл

		Для Каждого ТекущиеМетаданные Из ВидМетаданных Цикл

			Если СчетчикТаблиц = 256 Тогда
				ПакетЗапросов.Добавить(Новый Запрос(ТекстЗапроса));

				СчетчикТаблиц = 0;
				ТекстЗапроса  = "";
			КонецЕсли;

			СчетчикТаблиц = СчетчикТаблиц + 1;

			Если СчетчикТаблиц > 1 Тогда
				ТекстЗапроса = ТекстЗапроса + "				
											  |ОБЪЕДИНИТЬ ВСЕ";
			КонецЕсли;

			ТекстЗапроса = ТекстЗапроса + СтрЗаменить("
													  |ВЫБРАТЬ
													  |	""#ИмяТаблицы"" КАК ИмяТаблицы,
													  |	Т.Ссылка КАК Ссылка,
													  |	Т.ИмяПредопределенныхДанных КАК ИмяПредопределенныхДанных
													  |ИЗ
													  |	#ИмяТаблицы КАК Т
													  |ГДЕ
													  |	Т.ИмяПредопределенныхДанных <> """"", "#ИмяТаблицы",
				ТекущиеМетаданные.ПолноеИмя());

		КонецЦикла;

	КонецЦикла;

	Если СчетчикТаблиц > 1 Тогда
		ПакетЗапросов.Добавить(Новый Запрос(ТекстЗапроса));
	КонецЕсли;

	Для Каждого ТекущийЗапрос Из ПакетЗапросов Цикл

		Выборка = ТекущийЗапрос.Выполнить().Выбрать();
		Пока Выборка.Следующий() Цикл
			СтрокаПредопределенных = ТаблицаПредопределенных.Добавить();
			ЗаполнитьЗначенияСвойств(СтрокаПредопределенных, Выборка);
			СтрокаПредопределенных.ИмяТипаXML = XMLТипЗнч(СтрокаПредопределенных.Ссылка).ИмяТипа;
		КонецЦикла;
		Выборка = Неопределено;

	КонецЦикла;

	Возврат ТаблицаПредопределенных;

КонецФункции

// Параметры:
//   Данные - СправочникОбъект
//          - ДокументОбъект
//          - ПланСчетовОбъект
//          - ПланВидовРасчетаОбъект
//          - РегистрСведенийНаборЗаписей -
//            объект данных.
//   ТаблицаПредопределенных - см. ОбменДаннымиСлужебный.ТаблицаПредопределенныхДанных
// 
Процедура ОтметитьСсылкиНаПредопределенныеДанные(Данные, ТаблицаПредопределенных) Экспорт

	Если Данные = Неопределено Или ТипЗнч(Данные) = Тип("УдалениеОбъекта") Тогда
		Возврат;
	Иначе
		МетаданныеОбъекта = Данные.Метаданные();

		Если ОбщегоНазначения.ЭтоКонстанта(МетаданныеОбъекта) Тогда

			ПроверитьОтметитьСсылкуПредопределенных(Данные.Значение, ТаблицаПредопределенных);

		ИначеЕсли ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(МетаданныеОбъекта) Тогда

			МассивКоллекций = Новый Массив;
			МассивКоллекций.Добавить(МетаданныеОбъекта.Реквизиты);
			МассивКоллекций.Добавить(МетаданныеОбъекта.СтандартныеРеквизиты);

			Если ОбщегоНазначения.ЭтоЗадача(МетаданныеОбъекта) Тогда
				МассивКоллекций.Добавить(МетаданныеОбъекта.РеквизитыАдресации);
			КонецЕсли;

			ПроверитьОтметитьСсылкуПредопределенныхВКоллекцииРеквизитовОбъекта(Данные, МассивКоллекций,
				ТаблицаПредопределенных);

			Для Каждого ТабличнаяЧасть Из МетаданныеОбъекта.ТабличныеЧасти Цикл
				ПроверитьОтметитьСсылкуПредопределенныхВТаблицеДанных(Данные[ТабличнаяЧасть.Имя].Выгрузить(),
					ТаблицаПредопределенных);
			КонецЦикла;

			Если ОбщегоНазначения.ЭтоПланСчетов(МетаданныеОбъекта) Или ОбщегоНазначения.ЭтоПланВидовРасчета(
				МетаданныеОбъекта) Тогда
				Для Каждого ТабличнаяЧасть Из МетаданныеОбъекта.СтандартныеТабличныеЧасти Цикл
					ТабличнаяЧастьПланаСчетов = ТабличнаяЧасть; // ОбъектМетаданныхПланСчетов
					ПроверитьОтметитьСсылкуПредопределенныхВТаблицеДанных(
						Данные[ТабличнаяЧастьПланаСчетов.Имя].Выгрузить(), ТаблицаПредопределенных);
				КонецЦикла;
			КонецЕсли;

		ИначеЕсли ОбщегоНазначения.ЭтоРегистр(МетаданныеОбъекта) Тогда

			ПроверитьОтметитьСсылкуПредопределенныхВТаблицеДанных(Данные.Выгрузить(), ТаблицаПредопределенных);

		КонецЕсли;
	КонецЕсли;

КонецПроцедуры

// Параметры:
//   Данные - СправочникОбъект
//          - ДокументОбъект
//          - ПланСчетовОбъект
//          - РегистрСведенийНаборЗаписей - произвольный объект данных.
//   ТаблицаПредопределенных - см. ОбменДаннымиСлужебный.ТаблицаПредопределенныхДанных
// 
Процедура ЗаменитьСсылкиНаПредопределенныеЭлементы(Данные, ТаблицаПредопределенных) Экспорт

	Если Данные = Неопределено Или ТипЗнч(Данные) = Тип("УдалениеОбъекта") Тогда
		Возврат;
	Иначе
		МетаданныеОбъекта = Данные.Метаданные();

		Если ОбщегоНазначения.ЭтоКонстанта(МетаданныеОбъекта) Тогда

			ПроверитьЗаменитьСсылкуПредопределенногоВРеквизитеОбъекта(Данные, "Значение", ТаблицаПредопределенных);

		ИначеЕсли ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(МетаданныеОбъекта) Тогда

			ОбработатьЗагрузкуПредопределенногоЭлемента(Данные, ТаблицаПредопределенных);

			МассивКоллекций = Новый Массив;
			МассивКоллекций.Добавить(МетаданныеОбъекта.Реквизиты);
			МассивКоллекций.Добавить(МетаданныеОбъекта.СтандартныеРеквизиты);

			Если ОбщегоНазначения.ЭтоЗадача(МетаданныеОбъекта) Тогда
				МассивКоллекций.Добавить(МетаданныеОбъекта.РеквизитыАдресации);
			КонецЕсли;

			ПроверитьЗаменитьСсылкуПредопределенныхВКоллекцииРеквизитовОбъекта(Данные, МассивКоллекций,
				ТаблицаПредопределенных);

			Для Каждого ТабличнаяЧасть Из МетаданныеОбъекта.ТабличныеЧасти Цикл
				ПроверитьЗаменитьСсылкуПредопределенныхВТаблицеДанных(Данные[ТабличнаяЧасть.Имя],
					ТаблицаПредопределенных);
			КонецЦикла;

			Если ОбщегоНазначения.ЭтоПланСчетов(МетаданныеОбъекта) Или ОбщегоНазначения.ЭтоПланВидовРасчета(
				МетаданныеОбъекта) Тогда
				Для Каждого ТабличнаяЧасть Из МетаданныеОбъекта.СтандартныеТабличныеЧасти Цикл
					ТабличнаяЧастьПланаСчетов = ТабличнаяЧасть; // ОбъектМетаданныхПланСчетов
					ПроверитьЗаменитьСсылкуПредопределенныхВТаблицеДанных(Данные[ТабличнаяЧастьПланаСчетов.Имя],
						ТаблицаПредопределенных);
				КонецЦикла;
			КонецЕсли;

		ИначеЕсли ОбщегоНазначения.ЭтоРегистр(МетаданныеОбъекта) Тогда

			Для Каждого ЭлементОтбора Из Данные.Отбор Цикл
				СтруктураОтбора = Новый Структура("Значение, Использование");
				ЗаполнитьЗначенияСвойств(СтруктураОтбора, ЭлементОтбора);

				Если СтруктураОтбора.Использование = Ложь Тогда
					Продолжить;
				КонецЕсли;

				ПроверитьЗаменитьСсылкуПредопределенногоВРеквизитеОбъекта(СтруктураОтбора, "Значение",
					ТаблицаПредопределенных);
				ЭлементОтбора.Установить(СтруктураОтбора.Значение);
			КонецЦикла;

			ПроверитьЗаменитьСсылкуПредопределенныхВТаблицеДанных(Данные, ТаблицаПредопределенных);

		КонецЕсли;
	КонецЕсли;

КонецПроцедуры

#КонецОбласти

Функция СоставПланаОбмена(ИмяПланаОбмена, Периодические = Истина, Справочные = Истина) Экспорт

	Возврат ОбменДаннымиПовтИсп.СоставПланаОбмена(ИмяПланаОбмена, Периодические, Справочные);

КонецФункции

// Выполняет добавление информации об установленном в константе количестве элементов в транзакции
// в структуру, содержащую параметры транспорта сообщений обмена.
//
// Параметры:
//  Результат - Структура - содержит параметры транспорта сообщений обмена.
// 
Процедура ДополнитьНастройкиТранспортаКоличествомЭлементовВТранзакции(Результат) Экспорт

	Результат.Вставить("КоличествоЭлементовВТранзакцииВыгрузкиДанных",
		ОбменДаннымиСервер.КоличествоЭлементовВТранзакцииВыгрузкиДанных());
	Результат.Вставить("КоличествоЭлементовВТранзакцииЗагрузкиДанных",
		ОбменДаннымиСервер.КоличествоЭлементовВТранзакцииЗагрузкиДанных());

КонецПроцедуры

// Возвращает номер области по коду узла плана обмена (обмен сообщениями).
// 
// Параметры:
//  КодУзла - Строка - код узла плана обмена.
// 
// Возвращаемое значение:
//  Число - номер области.
//
Функция НомерОбластиИзКодаУзлаПланаОбмена(Знач КодУзла) Экспорт

	Если ТипЗнч(КодУзла) <> Тип("Строка") Тогда
		ВызватьИсключение НСтр("ru = 'Неправильный тип параметра номер [1].'");
	КонецЕсли;

	Результат = СтрЗаменить(КодУзла, "S0", "");

	Возврат Число(Результат);
КонецФункции

// Возвращает данные первой записи результата запроса в виде структуры.
// 
// Параметры:
//  РезультатЗапроса - РезультатЗапроса - результат запроса, содержащий данные для обработки.
// 
// Возвращаемое значение:
//  Структура - структура с результатом.
//
Функция РезультатЗапросаВСтруктуру(Знач РезультатЗапроса) Экспорт

	Результат = Новый Структура;
	Для Каждого Колонка Из РезультатЗапроса.Колонки Цикл
		Результат.Вставить(Колонка.Имя);
	КонецЦикла;

	Если РезультатЗапроса.Пустой() Тогда
		Возврат Результат;
	КонецЕсли;

	Выборка = РезультатЗапроса.Выбрать();
	Выборка.Следующий();

	ЗаполнитьЗначенияСвойств(Результат, Выборка);

	Возврат Результат;
КонецФункции

// Параметры:
//   Отбор - Отбор - произвольный отбор.
//   КлючЭлемента - Строка - имя элемента отбора.
//   ЗначениеЭлемента - Произвольный - значение элемента отбора.
// 
Процедура УстановитьЗначениеЭлементаОтбора(Отбор, КлючЭлемента, ЗначениеЭлемента) Экспорт

	ЭлементОтбора = Отбор.Найти(КлючЭлемента);
	Если ЭлементОтбора <> Неопределено Тогда
		ЭлементОтбора.Установить(ЗначениеЭлемента);
	КонецЕсли;

КонецПроцедуры

#Область РаботаСРегистрамиСведений

// Добавляет одну запись в регистр сведений по переданным значениям структуры.
//
// Параметры:
//  СтруктураЗаписи - Структура - структура, по значениям которой необходимо создать набор записей и заполнить этот
//                                набор.
//  ИмяРегистра     - Строка - имя регистра сведений, в который необходимо добавить запись.
// 
Процедура ДобавитьЗаписьВРегистрСведений(СтруктураЗаписи, Знач ИмяРегистра, Загрузка = Ложь) Экспорт

	НаборЗаписей = СоздатьНаборЗаписейРегистраСведений(СтруктураЗаписи, ИмяРегистра);
	
	// Добавляем только одну запись в новый набор записей.
	НоваяЗапись = НаборЗаписей.Добавить();
	
	// Заполняем значения свойств записи из переданной структуры.
	ЗаполнитьЗначенияСвойств(НоваяЗапись, СтруктураЗаписи);

	НаборЗаписей.ОбменДанными.Загрузка = Загрузка;
	
	// записываем набор записей
	НаборЗаписей.Записать();

КонецПроцедуры

// Обновляет запись в регистр сведений по переданным значениям структуры.
//
// Параметры:
//  СтруктураЗаписи - Структура - структура, по значениям которой необходимо создать менеджер записи и обновить запись.
//  ИмяРегистра     - Строка - имя регистра сведений, в котором необходимо обновить запись.
// 
Процедура ОбновитьЗаписьВРегистрСведений(СтруктураЗаписи, Знач ИмяРегистра) Экспорт

	МетаданныеРегистра = Метаданные.РегистрыСведений[ИмяРегистра]; // ОбъектМетаданныхРегистрСведений
	
	// Создаем менеджер записи регистра.
	МенеджерЗаписи = РегистрыСведений[ИмяРегистра].СоздатьМенеджерЗаписи();
	
	// Устанавливаем отбор по измерениям регистра.
	Для Каждого Измерение Из МетаданныеРегистра.Измерения Цикл

		ИмяИзмерения = Измерение.Имя;
		
		// Если задано значение в структуре, то отбор устанавливаем.
		Если СтруктураЗаписи.Свойство(ИмяИзмерения) Тогда

			МенеджерЗаписи[ИмяИзмерения] = СтруктураЗаписи[ИмяИзмерения];

		КонецЕсли;

	КонецЦикла;
	
	// Считываем запись из базы данных.
	МенеджерЗаписи.Прочитать();
	
	// Заполняем значения свойств записи из переданной структуры.
	ЗаполнитьЗначенияСвойств(МенеджерЗаписи, СтруктураЗаписи);
	
	// записываем менеджер записи
	МенеджерЗаписи.Записать();

КонецПроцедуры

// Удаляет набор записей в регистре по переданным значениям структуры.
//
// Параметры:
//  СтруктураЗаписи - Структура - структура, по значениям которой необходимо удалить набор записей.
//  ИмяРегистра     - Строка - имя регистра сведений, в котором необходимо удалить набор записей.
// 
Процедура УдалитьНаборЗаписейВРегистреСведений(СтруктураЗаписи, ИмяРегистра, Загрузка = Ложь) Экспорт

	НаборЗаписей = СоздатьНаборЗаписейРегистраСведений(СтруктураЗаписи, ИмяРегистра);

	НаборЗаписей.ОбменДанными.Загрузка = Загрузка;
	
	// записываем набор записей
	НаборЗаписей.Записать();

КонецПроцедуры

// Создает набор записей регистра сведений по переданным значениям структуры. Добавляет одну запись в набор.
//
// Параметры:
//  СтруктураЗаписи - Структура - структура по значениям которой необходимо создать набор записей и заполнить этот
//                                набор.
//  ИмяРегистра     - Строка - имя регистра сведений.
//  
// Возвращаемое значение:
//   РегистрСведенийНаборЗаписей - набор записей регистра по указанному отбору.
// 
Функция СоздатьНаборЗаписейРегистраСведений(СтруктураЗаписи, ИмяРегистра) Экспорт

	НаборЗаписей = РегистрыСведений[ИмяРегистра].СоздатьНаборЗаписей(); // РегистрСведенийНаборЗаписей
	
	// Устанавливаем отбор по измерениям регистра.
	Для Каждого КлючЗначение Из СтруктураЗаписи Цикл
		УстановитьЗначениеЭлементаОтбора(НаборЗаписей.Отбор, КлючЗначение.Ключ, КлючЗначение.Значение);
	КонецЦикла;

	Возврат НаборЗаписей;

КонецФункции

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Функция КомпонентыОбмена(НаправлениеОбмена, ПараметрыWEBСервиса, Отказ = Ложь)

	КомпонентыОбмена = ОбменДаннымиXDTOСервер.ИнициализироватьКомпонентыОбмена(НаправлениеОбмена);

	Если ЗначениеЗаполнено(ПараметрыWEBСервиса.ИмяПланаОбмена) И ЗначениеЗаполнено(
		ПараметрыWEBСервиса.КодУзлаПланаОбмена) Тогда
		КомпонентыОбмена.УзелКорреспондента = ПланыОбмена[ПараметрыWEBСервиса.ИмяПланаОбмена].НайтиПоКоду(
			ПараметрыWEBСервиса.КодУзлаПланаОбмена);
	Иначе
		КомпонентыОбмена.ЭтоОбменЧерезПланОбмена = Ложь;
	КонецЕсли;

	КомпонентыОбмена.ВедениеПротоколаДанных.ВыводВПротоколИнформационныхСообщений = Ложь;
	КомпонентыОбмена.СостояниеОбменаДанными.ДатаНачала = ТекущаяДатаСеанса();
	КомпонентыОбмена.ИспользоватьТранзакции = Ложь;

	Если НаправлениеОбмена = "Получение" Тогда

		КомпонентыОбмена.КлючСообщенияЖурналаРегистрации = СформироватьКлючСообщенияЖР(НаправлениеОбмена,
			ПараметрыWEBСервиса);

		ИмяФайла = ОбменДаннымиСервер.ПолучитьФайлИзХранилища(
			ПараметрыWEBСервиса.ИдентификаторФайлаВоВременномХранилище);
		ОбменДаннымиXDTOСервер.ОткрытьФайлЗагрузки(КомпонентыОбмена, ИмяФайла);
		ОбменДаннымиXDTOСервер.ПослеОткрытияФайлаЗагрузки(КомпонентыОбмена, Отказ);

		Если Отказ Тогда
			Возврат КомпонентыОбмена;
		КонецЕсли;

	Иначе

		КомпонентыОбмена.КлючСообщенияЖурналаРегистрации   = СформироватьКлючСообщенияЖР(НаправлениеОбмена,
			ПараметрыWEBСервиса);
		КомпонентыОбмена.ВерсияФорматаОбмена               = ОбменДаннымиXDTOСервер.ВерсияФорматаОбменаПриВыгрузке(
			КомпонентыОбмена.УзелКорреспондента);
		КомпонентыОбмена.XMLСхема                          = ОбменДаннымиXDTOСервер.ФорматОбмена(
			ПараметрыWEBСервиса.ИмяПланаОбмена, КомпонентыОбмена.ВерсияФорматаОбмена);
		КомпонентыОбмена.МенеджерОбмена                    = ОбменДаннымиXDTOСервер.МенеджерОбменаВерсииФормата(
			КомпонентыОбмена.ВерсияФорматаОбмена, КомпонентыОбмена.УзелКорреспондента);
		КомпонентыОбмена.ТаблицаПравилаРегистрацииОбъектов = ОбменДаннымиXDTOСервер.ПравилаРегистрацииОбъектов(
			КомпонентыОбмена.УзелКорреспондента);
		КомпонентыОбмена.СвойстваУзлаПланаОбмена           = ОбменДаннымиXDTOСервер.СвойстваУзлаПланаОбмена(
			КомпонентыОбмена.УзелКорреспондента);

	КонецЕсли;

	Если КомпонентыОбмена.ФлагОшибки Тогда
		Возврат КомпонентыОбмена;
	КонецЕсли;

	ОбменДаннымиXDTOСервер.ИнициализироватьТаблицыПравилОбмена(КомпонентыОбмена);

	Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена Тогда
		ОбменДаннымиXDTOСервер.ЗаполнитьСтруктуруНастроекXDTO(КомпонентыОбмена);
		ОбменДаннымиXDTOСервер.ЗаполнитьПоддерживаемыеОбъектыXDTO(КомпонентыОбмена);
	КонецЕсли;

	ОбменДаннымиXDTOСервер.ПослеИнициализацииКомпонентыОбмена(КомпонентыОбмена);

	Возврат КомпонентыОбмена;

КонецФункции

Функция ПолучитьИмяЧастиФайла(НомерЧастиФайла, ИмяАрхива = "")

	Если Не ЗначениеЗаполнено(ИмяАрхива) Тогда
		ИмяАрхива = "data";
	КонецЕсли;

	Результат = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("%1.zip.%2", ИмяАрхива, Формат(НомерЧастиФайла,
		"ЧГ=0"));

	Возврат Результат;

КонецФункции

Функция СостоянияФоновыхЗаданий()

	СостоянияФоновогоЗадания = Новый Соответствие;
	СостоянияФоновогоЗадания.Вставить(СостояниеФоновогоЗадания.Активно, "Active");
	СостоянияФоновогоЗадания.Вставить(СостояниеФоновогоЗадания.Завершено, "Completed");
	СостоянияФоновогоЗадания.Вставить(СостояниеФоновогоЗадания.ЗавершеноАварийно, "Failed");
	СостоянияФоновогоЗадания.Вставить(СостояниеФоновогоЗадания.Отменено, "Canceled");

	Возврат СостоянияФоновогоЗадания;

КонецФункции

Функция СформироватьКлючСообщенияЖР(НаправлениеОбмена, ПараметрыWEBСервиса)

	Если НаправлениеОбмена = "Получение" Тогда
		ШаблонКлючаСообщения = НСтр("ru = 'Загрузка данных через Web-сервис %1'", ОбщегоНазначения.КодОсновногоЯзыка());
	Иначе
		ШаблонКлючаСообщения = НСтр("ru = 'Выгрузка данных через Web-сервис %1'", ОбщегоНазначения.КодОсновногоЯзыка());
	КонецЕсли;

	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонКлючаСообщения,
		ПараметрыWEBСервиса.ИмяWEBСервиса);

КонецФункции

Функция СтруктураНастроекОбмена(КомпонентыОбмена, ДействиеОбменаДанными)

	Если Не КомпонентыОбмена.ЭтоОбменЧерезПланОбмена Тогда
		Возврат Неопределено;
	КонецЕсли;

	СтруктураНастроекОбмена = ОбменДаннымиСервер.НастройкиОбменаДляУзлаИнформационнойБазы(
		КомпонентыОбмена.УзелКорреспондента, ДействиеОбменаДанными, Неопределено, Ложь);

	Если СтруктураНастроекОбмена.Отказ Тогда
		СтрокаСообщенияОбОшибке = НСтр("ru = 'Ошибка при инициализации процесса обмена данными.'");
		ОбменДаннымиСервер.ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);
		ВызватьИсключение СтрокаСообщенияОбОшибке;
	КонецЕсли;

	СтруктураНастроекОбмена.РезультатВыполненияОбмена = Неопределено;
	СтруктураНастроекОбмена.ДатаНачала = ТекущаяДатаСеанса();

	СтрокаСообщения = НСтр("ru = 'Начало процесса обмена данными для узла %1'", ОбщегоНазначения.КодОсновногоЯзыка());
	СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения,
		СтруктураНастроекОбмена.УзелИнформационнойБазыНаименование);

	ЗаписьЖурналаРегистрации(СтруктураНастроекОбмена.КлючСообщенияЖурналаРегистрации,
		УровеньЖурналаРегистрации.Информация, СтруктураНастроекОбмена.УзелИнформационнойБазы.Метаданные(),
		СтруктураНастроекОбмена.УзелИнформационнойБазы, СтрокаСообщения);

	Возврат СтруктураНастроекОбмена;

КонецФункции

Процедура ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена, КомпонентыОбмена)

	Если Не КомпонентыОбмена.ЭтоОбменЧерезПланОбмена Тогда
		Возврат;
	КонецЕсли;

	СтруктураНастроекОбмена.РезультатВыполненияОбмена    = КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена;

	Если СтруктураНастроекОбмена.ДействиеПриОбмене = Перечисления.ДействияПриОбмене.ВыгрузкаДанных Тогда
		СтруктураНастроекОбмена.КоличествоОбъектовОбработано = КомпонентыОбмена.СчетчикВыгруженныхОбъектов;
		СтруктураНастроекОбмена.СообщениеПриОбмене           = СтруктураНастроекОбмена.ОбработкаОбменаДанными.КомментарийПриВыгрузкеДанных;
	ИначеЕсли СтруктураНастроекОбмена.ДействиеПриОбмене = Перечисления.ДействияПриОбмене.ЗагрузкаДанных Тогда
		СтруктураНастроекОбмена.КоличествоОбъектовОбработано = КомпонентыОбмена.СчетчикЗагруженныхОбъектов;
		СтруктураНастроекОбмена.СообщениеПриОбмене           = СтруктураНастроекОбмена.ОбработкаОбменаДанными.КомментарийПриЗагрузкеДанных;
	КонецЕсли;

	СтруктураНастроекОбмена.СтрокаСообщенияОбОшибке      = КомпонентыОбмена.СтрокаСообщенияОбОшибке;

	ОбменДаннымиСервер.ЗафиксироватьЗавершениеОбмена(СтруктураНастроекОбмена);

КонецПроцедуры

#Область ВыполнениеОбменаМетодамиСериализации

Процедура ПроверитьОтметитьСсылкуПредопределенных(Значение, ТаблицаПредопределенных)

	Если Не ОбщегоНазначения.ЭтоСсылка(ТипЗнч(Значение)) Тогда
		Возврат;
	КонецЕсли;

	СтрокаПредопределенных = ТаблицаПредопределенных.Найти(Значение, "Ссылка");
	Если СтрокаПредопределенных = Неопределено Тогда
		// Значение не является предопределенным элементом.
		Возврат;
	КонецЕсли;

	Если Не СтрокаПредопределенных.Выгружать Тогда
		СтрокаПредопределенных.Выгружать = Истина;
	КонецЕсли;

КонецПроцедуры

// Параметры:
//   Данные - Произвольный - объект данных.
//   МассивКоллекций - Массив из КоллекцияОбъектовМетаданных - набор коллекций реквизитов.
//   ТаблицаПредопределенных - ТаблицаЗначений - таблица предопределенных элементов.
// 
Процедура ПроверитьОтметитьСсылкуПредопределенныхВКоллекцииРеквизитовОбъекта(Данные, МассивКоллекций,
	ТаблицаПредопределенных)

	Для Каждого КоллекцияРеквизитов Из МассивКоллекций Цикл
		Для Каждого Реквизит Из КоллекцияРеквизитов Цикл
			ПроверитьОтметитьСсылкуПредопределенных(Данные[Реквизит.Имя], ТаблицаПредопределенных);
		КонецЦикла;
	КонецЦикла;

КонецПроцедуры

// Параметры:
//   ДанныеТаблицы - ТаблицаЗначений - таблица с данными объекта.
//   ТаблицаПредопределенных - ТаблицаЗначений - таблица предопределенных элементов.
// 
Процедура ПроверитьОтметитьСсылкуПредопределенныхВТаблицеДанных(ДанныеТаблицы, ТаблицаПредопределенных)

	Для Каждого СтрокаТаблицы Из ДанныеТаблицы Цикл
		Для Каждого Колонка Из ДанныеТаблицы.Колонки Цикл
			ПроверитьОтметитьСсылкуПредопределенных(СтрокаТаблицы[Колонка.Имя], ТаблицаПредопределенных);
		КонецЦикла;
	КонецЦикла;

КонецПроцедуры

// Параметры:
//   Данные - СправочникОбъект
//          - ПланВидовХарактеристикОбъект
//          - ПланСчетовОбъект
//          - ПланВидовРасчетаОбъект
//   ТаблицаПредопределенных - см. ОбменДаннымиСлужебный.ТаблицаПредопределенныхДанных
// 
Процедура ОбработатьЗагрузкуПредопределенногоЭлемента(Данные, ТаблицаПредопределенных)

	ИсходнаяСсылкаДанных = Данные.Ссылка;
	Если Данные.ЭтоНовый() Тогда
		ИсходнаяСсылкаДанных = Данные.ПолучитьСсылкуНового();
	КонецЕсли;

	СтрокаПредопределенные = ТаблицаПредопределенных.Найти(ИсходнаяСсылкаДанных, "ИсходнаяСсылка");
	Если СтрокаПредопределенные = Неопределено Тогда
		Возврат;
	КонецЕсли;

	ДанныеДляЗагрузки = СтрокаПредопределенные.Ссылка.ПолучитьОбъект();
	МетаданныеОбъекта = ДанныеДляЗагрузки.Метаданные();

	МассивКоллекций = Новый Массив;
	МассивКоллекций.Добавить(МетаданныеОбъекта.Реквизиты);
	МассивКоллекций.Добавить(МетаданныеОбъекта.СтандартныеРеквизиты);

	Если ОбщегоНазначения.ЭтоЗадача(МетаданныеОбъекта) Тогда
		МассивКоллекций.Добавить(МетаданныеОбъекта.РеквизитыАдресации);
	КонецЕсли;

	ПеренестиЗначенияКоллекцииРеквизитовМеждуОбъектами(Данные, ДанныеДляЗагрузки, МассивКоллекций);

	Для Каждого ТабличнаяЧасть Из МетаданныеОбъекта.ТабличныеЧасти Цикл
		Если Данные[ТабличнаяЧасть.Имя].Количество() > 0 Или ДанныеДляЗагрузки[ТабличнаяЧасть.Имя].Количество() > 0 Тогда
			ДанныеДляЗагрузки[ТабличнаяЧасть.Имя].Загрузить(Данные[ТабличнаяЧасть.Имя].Выгрузить());
		КонецЕсли;
	КонецЦикла;

	Если ОбщегоНазначения.ЭтоПланСчетов(МетаданныеОбъекта) Или ОбщегоНазначения.ЭтоПланВидовРасчета(МетаданныеОбъекта) Тогда
		Для Каждого ТабличнаяЧасть Из МетаданныеОбъекта.СтандартныеТабличныеЧасти Цикл
			Если Данные[ТабличнаяЧасть.Имя].Количество() > 0 Или ДанныеДляЗагрузки[ТабличнаяЧасть.Имя].Количество() > 0 Тогда
				ДанныеДляЗагрузки[ТабличнаяЧасть.Имя].Загрузить(Данные[ТабличнаяЧасть.Имя].Выгрузить());
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;

	Данные = ДанныеДляЗагрузки;

КонецПроцедуры

// Параметры:
//   Источник - Произвольный - объект-источник данных.
//   Приемник - Произвольный - объект-приемник данных.
//   МассивКоллекций - Массив из КоллекцияОбъектовМетаданных - набор коллекций реквизитов.
//
Процедура ПеренестиЗначенияКоллекцииРеквизитовМеждуОбъектами(Источник, Приемник, МассивКоллекций)

	Для Каждого КоллекцияРеквизитов Из МассивКоллекций Цикл
		Для Каждого Реквизит Из КоллекцияРеквизитов Цикл
			ИмяРеквизита = Реквизит.Имя;
			Если Приемник[ИмяРеквизита] = Приемник.Ссылка Тогда
				Продолжить;
			КонецЕсли;
			Если Приемник[ИмяРеквизита] = Источник[ИмяРеквизита] Тогда
				Продолжить;
			КонецЕсли;
			Приемник[ИмяРеквизита] = Источник[ИмяРеквизита];
		КонецЦикла;
	КонецЦикла;

КонецПроцедуры

// Параметры:
//   Данные - Произвольный - объект данных.
//   ИмяРеквизита - Строка - имя реквизита объекта.
//   ТаблицаПредопределенных - см. ОбменДаннымиСлужебный.ТаблицаПредопределенныхДанных
// 
Процедура ПроверитьЗаменитьСсылкуПредопределенногоВРеквизитеОбъекта(Данные, ИмяРеквизита, ТаблицаПредопределенных)

	Значение = Данные[ИмяРеквизита];

	Если Не ОбщегоНазначения.ЭтоСсылка(ТипЗнч(Значение)) Тогда
		Возврат;
	КонецЕсли;

	СтрокаПредопределенные = ТаблицаПредопределенных.Найти(Значение, "ИсходнаяСсылка");
	Если Не СтрокаПредопределенные = Неопределено Тогда
		Данные[ИмяРеквизита] = СтрокаПредопределенные.Ссылка;
	КонецЕсли;

КонецПроцедуры

// Параметры:
//   Данные - Произвольный - объект данных.
//   МассивКоллекций - Массив из КоллекцияОбъектовМетаданных - набор коллекций реквизитов.
//   ТаблицаПредопределенных - см. ОбменДаннымиСлужебный.ТаблицаПредопределенныхДанных
//
Процедура ПроверитьЗаменитьСсылкуПредопределенныхВКоллекцииРеквизитовОбъекта(Данные, МассивКоллекций,
	ТаблицаПредопределенных)

	Для Каждого КоллекцияРеквизитов Из МассивКоллекций Цикл
		Для Каждого Реквизит Из КоллекцияРеквизитов Цикл
			ПроверитьЗаменитьСсылкуПредопределенногоВРеквизитеОбъекта(Данные, Реквизит.Имя, ТаблицаПредопределенных);
		КонецЦикла;
	КонецЦикла;

КонецПроцедуры

// Параметры:
//   ДанныеТаблицы - ТабличнаяЧасть - табличная часть объекта или набор записей регистра.
//   ТаблицаПредопределенных - см. ОбменДаннымиСлужебный.ТаблицаПредопределенныхДанных
//
Процедура ПроверитьЗаменитьСсылкуПредопределенныхВТаблицеДанных(ДанныеТаблицы, ТаблицаПредопределенных)

	Если ДанныеТаблицы.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;

	ТаблицаТЧ = ДанныеТаблицы.Выгрузить();

	Для Каждого СтрокаТЧДанных Из ДанныеТаблицы Цикл
		Для Каждого Колонка Из ТаблицаТЧ.Колонки Цикл
			Если Не ОбщегоНазначенияКлиентСервер.ЕстьРеквизитИлиСвойствоОбъекта(СтрокаТЧДанных, Колонка.Имя) Тогда
				Продолжить;
			КонецЕсли;
			ПроверитьЗаменитьСсылкуПредопределенногоВРеквизитеОбъекта(СтрокаТЧДанных, Колонка.Имя,
				ТаблицаПредопределенных);
		КонецЦикла;
	КонецЦикла;

КонецПроцедуры

#Область УстаревшиеПроцедурыИФункции

// Устарела. Следует использовать ОбменДаннымиСервер.ПроверитьВозможностьВыполненияОбменов(Ложь).
//
Процедура ПроверитьВозможностьВыполненияОбменов() Экспорт

	Если Не ПравоДоступа("Просмотр", Метаданные.ОбщиеКоманды.Синхронизировать) Тогда

		ВызватьИсключение НСтр("ru = 'Недостаточно прав для синхронизации данных.'");

	ИначеЕсли ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы()
		И Не РежимЗагрузкиСообщенияОбменаДаннымиПередЗапуском("ЗагрузкаРазрешена") Тогда

		ВызватьИсключение НСтр("ru = 'Информационная база находится в состоянии обновления.'");

	КонецЕсли;

КонецПроцедуры

#КонецОбласти

#КонецОбласти

#КонецОбласти